#include <windows.h>
#include "elliott-common.h"
#include "elliott-DNS.h"


void makeDNSquestion(char* buf, string host1, string host2, string host3)
{
	int i = 0;
	buf[i++] = host1.length();
	memcpy(buf+i,host1.c_str(),sizeof(host1));
	i += host1.length();

	buf[i++] = host2.length();
	memcpy(buf+i,host2.c_str(),sizeof(host2));
	i += host2.length();

	buf[i++] = host3.length();
	memcpy(buf+i,host3.c_str(),sizeof(host3));
	i += host3.length();

	buf[i] = 0;
}

bool isHostName(char* name)
{
	if(name[0] == 0 || name[0] == 1 || name[0] == 2 || 
		name[0] == 3 || name[0] == 4 || name[0] == 5 || 
		name[0] == 6 || name[0] == 7 || name[0] == 8 || 
		name[0] == 9)
	{
		return false;
	}
	else
	{
		return true;
	}
}
void error(char *msg)
{
    perror(msg);
    exit(0);
}

int parseResponse(char* buf)
{
	fixedDNSheader dns_header;
	unsigned short *p = new unsigned short[6];
	memcpy((void*)&p,(void*)&buf,2);
	memcpy((void*)(&p+2),(void*)(&buf+2),2);
	memcpy((void*)(&p+4),(void*)(&buf+4),2);
	memcpy((void*)(&p+6),(void*)(&buf+6),2);
	memcpy((void*)(&p+8),(void*)(&buf+8),2);
	memcpy((void*)(&p+10),(void*)(&buf+10),2);
	dns_header.ID = ntohs(p[0]);
	dns_header.flags = ntohs(p[1]);
	dns_header.question_count = ntohs(p[2]);
	dns_header.answer_count = ntohs(p[3]);
	dns_header.authority_count = ntohs(p[4]);
	dns_header.additional_count = ntohs(p[5]);
	
	int queryspot = 12;

	/*char temp = buf[0];
	if(temp > 128)
	{
		dns_header.ID = 1;
		temp = temp & 127;
	}
	if(temp > 64)*/



	return 0;

}

int dnsLookup(char* host, bool isTypeA)
{
	WSADATA w;
	struct sockaddr_in server;
	char *sendbuf = NULL;
	char* host_name = "128.194.135.85";
	int buf_size = 1000;
	
	timeval* tp = new timeval();
	tp->tv_sec = 30;
	tp->tv_usec = 0;


	/* Open windows connection */
	if (WSAStartup(0x0101, &w) != 0)
	{
		fprintf(stderr, "Could not open Windows connection.\n");
		return 1;
	}

	/* Open a datagram socket */
	SOCKET sd = socket(AF_INET, SOCK_DGRAM, 0);
	if (sd == INVALID_SOCKET)
	{
		fprintf(stderr, "Could not create socket.\n");
		WSACleanup();
		return 1;
	}

	/* Clear out server struct */
	memset((void *)&server, '\0', sizeof(struct sockaddr_in));

	/* Set family and port */
	server.sin_family = AF_INET;
	server.sin_port = htons((unsigned short)53);
	if((server.sin_addr.s_addr = inet_addr(host_name))== INADDR_NONE)
	{
		printf("problema?");
	}
	
	//TYPE A Query Construction
	if(isTypeA)
	{
		int count = 0;
		while (count++ < 3) {

			int pkt_size = ((string)host).length() + 2 + sizeof(fixedDNSheader) + 4; 
			 
			char *buf = new char [pkt_size];
			 
			fixedDNSheader *dns_header = (fixedDNSheader *) buf; 
			queryHeader *query_header = (queryHeader*) (buf + pkt_size - 4);//sizeof(queryHeader));


			char *hostName = (char *)(buf + sizeof(fixedDNSheader));
			hostName = "www.google.com";

			// fixed field initialization 
			dns_header->ID = htons((unsigned short) 1);
			dns_header->flags = htons(DNS_QUERY | DNS_STDQUERY | DNS_RD);//htons((unsigned short) 256);
			dns_header->question_count = htons((unsigned short) 1);
			dns_header->answer_count = htons((unsigned short) 0);
			dns_header->authority_count = htons((unsigned short) 0);
			dns_header->additional_count = htons((unsigned short) 0);
			
			makeDNSquestion(buf + sizeof(fixedDNSheader) , (string)"www", (string)"google", (string)"com"); 
			
			query_header->type = htons(DNS_A);
			query_header->query_class = htons(DNS_INET);
			
			sendto (sd, buf, pkt_size,0,(SOCKADDR *)&server, sizeof(server)); 
			//delete buf;

			// get ready to receive

			char* recv_buf = new char[buf_size];
			fd_set fd; 
			FD_ZERO (&fd);    // clear the set 
			FD_SET (sd, &fd); // add your socket to the set 


			//server.sin_port = htons(60465);
			//int bindNum = bind(sd,(sockaddr *)&server, sizeof(server));
			int available = select (0, &fd, NULL, NULL,tp); 
			if (available > 0) { 
				printf("Available: %d\n",available);
				

				recvfrom(sd, recv_buf, buf_size,0,(SOCKADDR *)&server, (int*)sizeof(server));

				for(int i = 0; i < 999; i++)
				{
					printf("Recv_buf: %c%c\n",recv_buf[i],recv_buf[i+1]);
				}
				//printf("\n%hhx %c\n%hhx %c\n",ntohs((unsigned short) &recv),ntohs((unsigned short) &recv),recv,recv);

				//printf("Recv_buf:\n%c\n",recv_buf);

				parseResponse(recv_buf);
				// parse the response 
				// break from the loop 

				
				count = 4;
			} 
		}
	}

	//TYPE PTR Query Construction
	else
	{
		/*
		int count = 0;
		while (count++ < 3) { 

			int pkt_size = ((string)host).length() + 2 + sizeof(fixedDNSheader) + 4; 
			 
			char *buf = new char [pkt_size];
			 
			fixedDNSheader *dns_header = (fixedDNSheader *) buf; 
			queryHeader *query_header = (queryHeader*) (buf + pkt_size - 4);//sizeof(queryHeader));


			char *hostName = (char *)(buf + sizeof(fixedDNSheader));
			hostName = "74.125.65.99";

			// fixed field initialization 
			dns_header->ID = htons((unsigned short) 1);
			dns_header->flags = htons(DNS_QUERY | DNS_STDQUERY | DNS_RD);//htons((unsigned short) 256);
			dns_header->question_count = htons((unsigned short) 1);
			dns_header->answer_count = htons((unsigned short) 0);
			dns_header->authority_count = htons((unsigned short) 0);
			dns_header->additional_count = htons((unsigned short) 0);
			
			//makeDNSquestion(buf + sizeof(fixedDNSheader) , (string)"www", (string)"google", (string)"com"); 
			
			query_header->type = htons(DNS_PTR);
			query_header->query_class = htons(DNS_INET);

			sendto (sd, buf, pkt_size,0,(SOCKADDR *)&server, sizeof(server)); 
			//delete buf;
			// get ready to receive 

			fd_set fd; 
			FD_ZERO (&fd);    // clear the set 
			FD_SET (sd, &fd); // add your socket to the set 
			int available = select (0, &fd, NULL, NULL,tp); 
			if (available > 0) { 
				printf("Available: %d\n",available);
				//bind(sd, (SOCKADDR *)&server, sizeof(server));
				recvfrom(sd, recv_buf, buf_size,0,(SOCKADDR *)&server, (int *)sizeof(server));

				printf("Recv_buf:\n%s\n",recv_buf);
				// parse the response 
				// break from the loop 

				count = 4;
			}
		} */
	}
	 	// some error checking here

	closesocket(sd);
	GlobalFree(sendbuf);
	WSACleanup();
	return 0;
}

int main(int argc,char* argv[])
{

	char* name;
	if(argc > 1)
		name = argv[1];
	else 
		name = "www.google.com";

	bool usingHostName = isHostName(name);
	if(!usingHostName)
	{
		if(inet_addr(name) == INADDR_NONE)
		{
			printf("not a valid IP\n");
			return 1;
		}
	}

	dnsLookup(name,usingHostName);

	return 0;

}